Skip to content

Prompt Tier 0: derive risk appetite, pairing and band tiers (T0.1–T0.3) - #39

Merged
GustavoSena merged 1 commit into
mainfrom
gs/prompt-tier-0-echo-dont-compute
Jul 26, 2026
Merged

Prompt Tier 0: derive risk appetite, pairing and band tiers (T0.1–T0.3)#39
GustavoSena merged 1 commit into
mainfrom
gs/prompt-tier-0-echo-dont-compute

Conversation

@GustavoSena

Copy link
Copy Markdown
Collaborator

Closes #24, #25, #26. Tier 0 of the prompt ladder (#29) — the prompt-side half; #38 is the validator-side half.

The principle

The composer model is qwen/qwen2.5-omni-7b with two attempts before the deterministic fallback and a user watching a spinner. It has already been caught fabricating chainIds and deadlines until the prompt said "copy these EXACTLY". So: deterministic code computes, the model echoes. Three seams where the prompt was still asking a 7B model to work something out for itself:

New module Was asking the model to… Now
appetite.ts (#24) infer risk inclination from the user's wording, mid-JSON-emission a lexicon classifies it; the prompt states it as a fact
pairing.ts (#25) divide a budget by a mid price across two decimal scales the value-matched pair and per-strategy share are computed
tiers.ts (#26) pick band widths three widths derived from volatility, shifted by appetite

No new data source, no extra round trip, no schema change, no validator change.

What each one buys

#25 is the one with teeth. The ratio of a strategy's virtualAmounts is its shipped price. A model that divides wrong ships an off-mid strategy — free money for the first taker — and nothing in the validator catches that today (a price-vs-mid invariant is Tier 2). The plan is the largest mid-consistent pair fitting both ceilings: 2 WETH against 3000 USDC at mid 3450 can only use 0.869565 WETH, because committing both ceilings in full would ship a price that is not the mid. Exact fixed-point throughout, and per-strategy shares truncate down, so N shares satisfy I2 by construction rather than by the model's arithmetic.

#26 gets risk tiering with no market data, because on a single pair the risk axis already exists: band width. Tighter quotes deeper (more fill volume) and exhausts on a smaller move — grammar.ts states exactly that trade-off. Appetite shifts the whole set, which is the "5/7/9 instead of 3/5/7" behaviour in band space:

conservative   wide ±24.10%   mid ±12.05%   tight ±6.02%
aggressive     wide  ±8.03%   mid  ±4.02%   tight ±2.01%

Two calibration decisions, stated rather than buried

  1. Volatility is read as ANNUALISED. The field is realizedVol7dPct, which does not settle it. 58 is the canonical annualised ETH figure, and the other reading produces ±87%–±99% bands — full-range in all but name, not a market-making recommendation. The two differ by ~3.5x, so this needs confirming when F3 Open Q2 lands a real source (the field may want renaming then). A test pins it: any neutral tier above ±25% means the annualised reading has been lost.
  2. Tier labels describe mechanics, never yield. No fee-APR source exists yet, and rating a recommendation is Gate 2's job (F2 §4, deferred) — the app already says "risk rating unavailable". Conditioning band width on what the user said is a different claim from us rating risk. A test forbids projected-return language in the block.

Honesty and failure modes

  • Every block is omitted rather than faked when its inputs are missing: a single-token budget gets no pairing block (no invented counterpart), an unusable mid gets none (no fabricated price), a request that cannot carry three strategies gets no tier block.
  • The tier block no longer references REFERENCE PAIRING when that block was not rendered — a test caught the dangling pointer, which is exactly the sort of thing that invites a 7B model to invent one. It now states the I2 divide-don't-repeat rule instead.
  • Tiers inherit the pair data's STUB label, the same way contextPromptBlock does; both flip together when F3 Q2 settles.

PROMPT_VERSIONsluice.compose/3 (F2 §9).

Verification

  • SDK 169/169, typecheck clean. 41 new tests: appetite (incl. ties → neutral, "unsafe" ≠ "safe"), pairing (binding side both ways, implied price reproduces the mid, truncation direction, IEEE-754 trap, null cases), tiers (monotonicity, encodable range across a vol × horizon × appetite sweep, degenerate and extreme vol, label/number agreement), plus prompt-integration assertions that the derived values actually reach the message and that feedback still lands last.
  • App typecheck + build green (untouched, but it consumes the SDK).
  • The rendered prompt was read end-to-end by eye — that is how the ±99% band problem was caught.

Not in this PR

#28 (the baseline-anchoring spike) needs a funded Galileo key to measure anything, so it stays open. The UI still maps risk from band presence in from-server.ts; wiring tier labels through to the screen is a follow-up, and it should be reconciled with the "risk rating unavailable" decision first.

🤖 Generated with Claude Code

)

Three things the composer asked a 7B model to work out for itself, now
computed deterministically and handed over as values to echo. No new data
source, no extra inference round trip, no schema change.

- appetite.ts (#24): reads the user's risk wording with a small lexicon.
  Classification never goes to the model — mixing it into a JSON-emission
  task costs output validity, and there is one retry.
- pairing.ts (#25): the largest mid-consistent pair that fits BOTH
  ceilings, plus its per-strategy share. The ratio of virtualAmounts IS
  the shipped price, so a model dividing a budget by a mid across two
  decimal scales ships an off-mid strategy — free money for the first
  taker, and nothing in the validator catches it today. Exact fixed-point
  throughout; shares truncate DOWN, so N of them satisfy I2 by
  construction.
- tiers.ts (#26): risk tiering with no new market data, because on one
  pair band width IS the risk axis. Three widths from realised volatility,
  shifted by appetite — the "5/7/9 instead of 3/5/7" behaviour, expressed
  in band space.

Two calibration decisions, stated rather than buried. Volatility is read
as ANNUALISED (58 is the canonical ETH figure; the other reading gives
±87%–±99% bands, which are full-range in all but name) — recheck when F3
Q2 lands a real source. And tier labels describe MECHANICS, never yield:
we have no fee-APR source, and rating a recommendation is Gate 2's job.

Every block is omitted rather than faked when its inputs are missing, and
the tier block no longer points at a REFERENCE PAIRING that was not
rendered — a dangling reference is an invitation to invent one.

PROMPT_VERSION -> sluice.compose/3 (F2 §9).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Prompt T0.1 — deterministic risk-appetite classifier, rendered as one prompt line

1 participant